﻿package rob.parser{
	import flash.net.URLLoader
	import flash.net.URLRequest;
	import flash.events.Event;
	import flash.display.Sprite;
	import rob.core.Ini;
	import rob.core.Mesh3d;
	import rob.data.*;
	
	
	/* note: only using sprite for immediate event listening */
	public class ParserOBJ extends Sprite{
		private static var _instance = undefined;
		private var _loadMTL:URLLoader, _loadOBJ:URLLoader;
		private var _mtlData:String, _objData:String;
		private var _mtlLoaded:Boolean, _objLoaded:Boolean;
		private var _filenames:Array, _folder:String;
		private var _meshes:Array;
		private var _parseCount:Number;
		public var parsed:Boolean;
		
		public function ParserOBJ():void{
			_loadMTL = new URLLoader();
			_loadOBJ = new URLLoader();
			_filenames = [];
			_meshes = [];
			_materials = [];
			_folder = Ini.instance.objDirectory;
			_loadMTL.addEventListener(Event.COMPLETE, _recMTL);
			_loadOBJ.addEventListener(Event.COMPLETE, _recOBJ);	
			// parser continually checks if mtl/obj both loaded
			this.addEventListener(Event.ENTER_FRAME,_parse);
		}
		
		// assume at least one file to be loaded
		public function loadMeshes():void{
			var f:String = _filenames.shift();
			var url:String, req:URLRequest;
			_parseCount = 0;
			// material
			url= _folder + f + ".mtl";
			req = new URLRequest(url);
			_loadMTL.load(req);
			// mesh
			url= _folder + f + ".obj";
			req = new URLRequest(url);
			_loadOBJ.load(req);

		}
		// receive MTL data
		private function _recMTL(evt:Event){
			_mtlData = _loadMTL.data;
			_mtlLoaded = true;
		}
		// receive OBJ data
		private function _recOBJ(evt:Event){
			_objData = _loadOBJ.data;
			_objLoaded = true;
		}
	
		private function _parse(evt:Event):void{
			var mtlLines:Array, objLines:Array, line:String;
			var bs:Array, bss:Array, face:Array, uvface:Array, meshName:String;
			var verts:Array, uvs:Array, faces:Array, currMat:String;
			var matName:String, textured:Boolean, matColour:RGB, foundMaterial:Boolean;
			var gouraud:Boolean;
			textured = gouraud = foundMaterial = false;
			
			if(_mtlLoaded && _objLoaded){
				// PARSE MTL and OBJ file
				// -- files now expected to be a SINGLE mesh
					// first get materials
					mtlLines = _mtlData.split("\r\n");
					for each(line in mtlLines){
						bs = line.split(" ");
						switch(bs[0]){
							case "newmtl":	matName = bs[1]; foundMaterial=true; break;
							case "map_Kd":	textured = true; break;
							case "Kd":		matColour = new RGB(255*bs[1],255*bs[2],255*bs[3]); break;
							case "":		
									if(foundMaterial){
										// if material starts 'g_' then use gouraud shading
											bs = matName.split("g_");
											if(bs.length==2) gouraud = true;
										// create material
										_materials[matName] = new Material(matName,textured,gouraud,matColour);
										// reset
										textured = gouraud = foundMaterial = false;
									}
						}
					}
					// now get mesh
					objLines = _objData.split("\r\n");
					verts = [];	faces = [];	uvs = [];
					for each(line in objLines){
						bs = line.split(" ");
						switch(bs[0]){
							case "o":	meshName = bs[1]; break;
							case "v":	verts.push(new Vert3d(bs[1],bs[2],bs[3])); break;
							case "vt":	uvs.push(new UVCoord(bs[1],bs[2])); break;
							case "usemtl":	currMat = bs[1]; break
							case "f":
								face = [];	uvface = [];
								for(var i:Number=1;i < bs.length;i++){
									bss = bs[i].split("/");
									face[i-1]=bss[0] - 1;
									uvface[i-1]=bss[1] - 1;
								}
								faces.push({mat:currMat, face:face, uvface:uvface});
						}
					}
					// now construct a mesh
					_meshes[meshName] = new Mesh3d(meshName,verts,uvs,faces);
					trace("Loaded mesh: " + meshName);
					
				// reset
				_mtlData = _objData = "";
				_mtlLoaded = _objLoaded = false;
				// load each filename
				if(_filenames.length != 0) loadMeshes();
				// if finished then stop listening
				else{
					this.parsed = true;
					this.removeEventListener(Event.ENTER_FRAME,_parse);
				}
				_parseCount==0;
			}
			else _parseCount++;
			
			//trace(_parseCount);
		}
		public function getMeshByName(name:String):Mesh3d{
			return _meshes[name];
		}
	
		public function getMaterialByName(name:String):Material{
			return _materials[name];
		}
	
		public static function get instance():ParserOBJ{
			if(_instance == undefined) _instance = new ParserOBJ();
			return _instance;
		}
		public function set filenames(f:Array):void{
			_filenames = f;
		}
	}
}